const XLSX = require('xlsx');
const XLSXJS = require('xlsx-style');
const ExcelJS = require('exceljs');
const fs = require('fs-extra');
const path = require('path');
const mkdirp = require('mkdirp');
const archiver = require('archiver');
const { encryptStr, pushNotification } = require('./pushUtils');

// 定义日志文件路径
const isPackaged = !!process.pkg; // 假设使用 pkg 打包，process.pkg 存在表示打包为 exe
// 定义日志文件路径
const LOGS_DIR = isPackaged ? path.join(path.dirname(process.execPath), 'logs_exe') : path.join(__dirname, 'logs');
const LOG_FILE_PATH = path.join(LOGS_DIR, 'app.log');

// 自定义日志函数，同时输出到控制台和文件
function logToFile(...args) {
  // 使用全局 console.log，避免被覆盖
  global.console.log(...args);

  // 格式化日志消息，带时间戳
  const timestamp = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
  const message = args
    .map(arg => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : arg))
    .join(' ');
  const logMessage = `[${timestamp}] ${message}\n`;

  try {
    // 确保 logs 目录存在
    fs.ensureDirSync(LOGS_DIR);
    // 追加写入日志文件
    fs.appendFileSync(LOG_FILE_PATH, logMessage, 'utf8');
  } catch (error) {
    global.console.error(`写入日志文件失败: ${error.message}`);
  }
}

// 辅助函数：四舍五入到小数点后 2 位
function roundToTwo(num) {
  return Math.round(num * 100) / 100;
}

// 向上取整
function ceilToInteger(num) {
  // 处理 NaN 和无穷大的情况
  if (!isFinite(num)) return num;
  
  // 直接使用 Math.ceil 向上取整到整数
  return Math.ceil(num);
}

// 文件路径
const INPUT_FILE_PATH = isPackaged ? path.join(path.dirname(process.execPath), '收利穿透明白纸.xlsx') : path.join(__dirname, '收利穿透明白纸.xlsx');
const INPUT_FILE_USER_PATH = isPackaged ? path.join(path.dirname(process.execPath), '人员信息.xlsx') : path.join(__dirname, '人员信息.xlsx');
const OUTPUT_DIR = isPackaged ? path.join(path.dirname(process.execPath), 'files_exe') : path.join(__dirname, 'files');
const SUB_DIRS = {
  county: path.join(OUTPUT_DIR, 'county'), // 区县子目录
  branch: path.join(OUTPUT_DIR, 'branch'), // 支局子目录
  personnel: path.join(OUTPUT_DIR, 'personnel') // 人员子目录
};
const TEMPLATE_PATHS = {
  district: path.join(__dirname, 'tmpFiles', 'county.xlsx'),
  branch: path.join(__dirname, 'tmpFiles', 'branch.xlsx'),
  personnel: path.join(__dirname, 'tmpFiles', 'personnel.xlsx')
};

// 函数：打包目录为 zip
async function zipDirectory(sourceDir, outputZipPath) {
  return new Promise((resolve, reject) => {
    const archive = archiver('zip', { zlib: { level: 9 } });
    const output = fs.createWriteStream(outputZipPath);
    output.on('close', () => resolve());
    archive.on('error', (err) => reject(err));
    archive.pipe(output);
    archive.directory(sourceDir, false);
    archive.finalize();
  });
}

// 函数：读取并解析输入的 Excel 文件
function readInputExcel() {
  logToFile('正在读取数据文件 收利穿透明白纸.xlsx');
  if (!fs.existsSync(INPUT_FILE_PATH)) {
    throw new Error('未找到输入文件：收利穿透明白纸.xlsx');
  }
  const workbook = XLSX.readFile(INPUT_FILE_PATH, { cellStyles: true });
  const sheets = {};
  workbook.SheetNames.forEach(name => {
    sheets[name] = XLSX.utils.sheet_to_json(workbook.Sheets[name], { header: 1 });
  });
  return sheets;
}

// 函数：读取并解析输入的用户Excel 文件
function readInputUserExcel() {
  logToFile('正在读取数据文件 人员数据文件.xlsx');
  if (!fs.existsSync(INPUT_FILE_USER_PATH)) {
    throw new Error('未找到输入文件：人员数据文件.xlsx');
  }
  const workbook = XLSX.readFile(INPUT_FILE_PATH, { cellStyles: true });
  const sheets = {};
  workbook.SheetNames.forEach(name => {
    sheets[name] = XLSX.utils.sheet_to_json(workbook.Sheets[name], { header: 1 });
  });
  return sheets;
}

// 函数：读取模板文件（保留样式和格式）
function readTemplate(templatePath, templateName) {
  if (!fs.existsSync(templatePath)) {
    throw new Error(`未找到模板文件：${templateName}`);
  }
  
  // 直接读取整个工作簿，不进行JSON转换
  const workbook = XLSXJS.readFile(templatePath, {
    cellStyles: true,
    cellNF: true,      // 保留数字格式
    sheetStubs: true,  // 保留空白单元格
    bookVBA: true      // 保留VBA（如果有）
  });
  
  return workbook;
}

// 函数：深度复制工作簿（完整保留样式）
function cloneWorkbook(originalWorkbook) {
  const clonedWorkbook = XLSX.utils.book_new();
  
  // 复制工作簿级别的样式表（重要！）
  if (originalWorkbook.Styles) {
    clonedWorkbook.Styles = JSON.parse(JSON.stringify(originalWorkbook.Styles));
  }
  
  // 复制共享字符串表（如果存在）
  if (originalWorkbook.SSF) {
    clonedWorkbook.SSF = { ...originalWorkbook.SSF };
  }
  
  // 复制其他工作簿属性
  if (originalWorkbook.Props) {
    clonedWorkbook.Props = JSON.parse(JSON.stringify(originalWorkbook.Props));
  }
  
  if (originalWorkbook.Custprops) {
    clonedWorkbook.Custprops = JSON.parse(JSON.stringify(originalWorkbook.Custprops));
  }
  
  originalWorkbook.SheetNames.forEach(sheetName => {
    const originalWs = originalWorkbook.Sheets[sheetName];
    const clonedWs = {};
    
    // 复制所有单元格，包括样式信息
    Object.keys(originalWs).forEach(cellAddr => {
      if (cellAddr[0] === '!') return;
      
      const originalCell = originalWs[cellAddr];
      clonedWs[cellAddr] = {};
      
      // 复制单元格的所有属性
      Object.keys(originalCell).forEach(prop => {
        if (typeof originalCell[prop] === 'object' && originalCell[prop] !== null) {
          // 深度复制对象属性（如样式对象 s）
          clonedWs[cellAddr][prop] = JSON.parse(JSON.stringify(originalCell[prop]));
        } else {
          clonedWs[cellAddr][prop] = originalCell[prop];
        }
      });
    });
    
    // 复制工作表级别的特殊属性
    clonedWs['!ref'] = originalWs['!ref'];
    
    if (originalWs['!merges']) {
      clonedWs['!merges'] = originalWs['!merges'].map(merge => ({ ...merge }));
    }
    
    if (originalWs['!cols']) {
      clonedWs['!cols'] = originalWs['!cols'].map(col => col ? { ...col } : col);
    }
    
    if (originalWs['!rows']) {
      clonedWs['!rows'] = originalWs['!rows'].map(row => row ? { ...row } : row);
    }
    
    // 复制其他可能影响样式的属性
    if (originalWs['!margin']) {
      clonedWs['!margin'] = { ...originalWs['!margin'] };
    }
    
    if (originalWs['!pageSetup']) {
      clonedWs['!pageSetup'] = { ...originalWs['!pageSetup'] };
    }
    
    if (originalWs['!printOptions']) {
      clonedWs['!printOptions'] = { ...originalWs['!printOptions'] };
    }
    
    XLSX.utils.book_append_sheet(clonedWorkbook, clonedWs, sheetName);
  });
  
  return clonedWorkbook;
}

// 函数：根据 sheet 数据生成区县报告
async function generateDistrictReports(sheets,personnelInfo) {
  logToFile('生成区县报告...');
  if (!sheets['发展量&收入&成本目标 分解--区县']) {
    logToFile(`未找到 sheet "发展量&收入&成本目标 分解--区县"，请检查数据文件sheet名称。`);
    process.exit(1);
  }
  const districtDevData = sheets['发展量&收入&成本目标 分解--区县'] || [];

  // 加载模板一次
  const templateWorkbook = readTemplate(TEMPLATE_PATHS.district, 'county.xlsx');
  const sheetName = templateWorkbook.SheetNames[0];
  const templateWs = templateWorkbook.Sheets[sheetName];

  // 全局修复 &#10; 一次
  Object.keys(templateWs).forEach(cellAddr => {
    const cell = templateWs[cellAddr];
    if (cell && cell.t === 's' && typeof cell.v === 'string' && cell.v.includes('&#10;')) {
      cell.v = cell.v.replace(/&#10;/g, '\n');
    }
  });

  //区县发展量数据
  const districts = {};
  districtDevData.slice(3).forEach((row, index) => {
    if (row[0] && row.length > 1 && row[0] != '分解部门') {
      const districtName = row[0].trim(); // 区县名称
      districts[districtName] = Array.from(row, v => v ?? 0); // 填充空值，确保数据完整
    } 
  });

  for (const [districtName, devRow] of Object.entries(districts)) {

    // 克隆模板
    const workbook = cloneWorkbook(templateWorkbook);
    const ws = workbook.Sheets[sheetName];

    // 直接修改模板中的单元格值，保持原有格式
    const updateCell = (cell, value) => {
      if (!ws[cell]) {
        // 如果单元格不存在，创建基本结构
        ws[cell] = { t: typeof value === 'number' ? 'n' : 's', v: value };
      } else {
        // 保留原有样式，只更新值
        ws[cell].v = value;
        ws[cell].t = typeof value === 'number' ? 'n' : 's';
      }
    };

    // 定义重复使用的中间变量
    const fullRevenue = (devRow[22] ?? 0) + (devRow[24] ?? 0) + (devRow[23] ?? 0); // 全业务收入
    const resourceCost = (devRow[23] ?? 0) * 0.2; // 产数资源型成本
    const depreciationAmortization = devRow[61] ?? 0; // 折旧摊销
    const controllableCostSum = ((devRow[31] ?? 0) + (devRow[32] ?? 0) + (devRow[50] ?? 0) + (devRow[51] ?? 0) + (devRow[48] ?? 0) + (devRow[43] ?? 0) + (devRow[44] ?? 0)); // 可控成本合计
    const interOperatorSettlement = devRow[33] ?? 0; // 网间结算
    const otherCostSum = (
        (devRow[58] ?? 0) +  // 展广费-校园
        (devRow[30] ?? 0) +   // 固网终端
        (devRow[29] ?? 0) +   // 包区包镇
        (devRow[28] ?? 0) +   // 社会渠道费
        (devRow[26] ?? 0) +   // 外包费
        (devRow[60] ?? 0) +  // ICT成本
        interOperatorSettlement +  // 网间结算
        (devRow[36] ?? 0) +  // 电费-营业厅
        (devRow[37] ?? 0) +  // 电费-办公
        (devRow[38] ?? 0) +  // 电费-机房基站
        (devRow[39] ?? 0) +  // 电费-铁塔电费
        (devRow[40] ?? 0) +  // 租费-机房基站网元
        (devRow[41] ?? 0) +  // 租费-铁塔站址
        (devRow[42] ?? 0) +  // 修理费-网络类
        (devRow[45] ?? 0) +  // 共建共享
        (devRow[46] ?? 0) +  // 装移机料费
        (devRow[25] ?? 0) +   // 人工成本
        (devRow[27] ?? 0) +   // 四小补贴
        (devRow[34] ?? 0) +  // 营业厅房租
        (devRow[35] ?? 0) +  // 营业厅装修
        (devRow[47] ?? 0) +  // 办公类低值易耗
        (devRow[49] ?? 0) +  // 邮寄费
        (devRow[52] ?? 0) +  // 租费
        (devRow[53] ?? 0) +  // 物业费
        (devRow[54] ?? 0) +  // 水费
        (devRow[55] ?? 0) +  // 取暖费
        (devRow[56] ?? 0) +  // 车辆使用费
        (devRow[57] ?? 0) +  // 校园-房租
        (devRow[59] ?? 0) +  // 学子公司
        depreciationAmortization +  // 折旧摊销
        resourceCost  // 产数资源型成本
    );; // 其他成本合计
    const totalCostAssessment = controllableCostSum + otherCostSum - interOperatorSettlement - depreciationAmortization - resourceCost; // 考核口径成本合计
    const totalCostEvaluation = controllableCostSum + otherCostSum; // 评价口径成本合计

    // 区县名称
    updateCell('D2', districtName ?? '');// 区县名称（字符串）
    
    // 第7行：收入线-量
    updateCell('C7', devRow[1] ?? 0);// 移动用户年净增（万户）
    updateCell('D7', devRow[2] ?? 0);// 移动用户年新增（万户）
    updateCell('E7', devRow[3] ?? 0);// 宽带用户年净增（万户）
    updateCell('F7', devRow[4] ?? 0);// 宽带用户年新增（万户）
    updateCell('G7', ceilToInteger(devRow[5] ?? '0'));// 151集智融合日新增（户）
    updateCell('H7', ceilToInteger(devRow[6] ?? '0'));// FTTR日新增（户）
    updateCell('I7', devRow[7] ?? 0);// 高清年新增（万户）
    updateCell('J7', ceilToInteger(devRow[8] ?? '0'));// 天翼视联日新增（户）
    updateCell('K7', ceilToInteger(devRow[9] ?? '0'));// 小翼管家日新增（户）
    updateCell('L7', ceilToInteger(devRow[10] ?? '0'));// 量子密话年新增（户）
    updateCell('M7', ceilToInteger(devRow[11] ?? '0'));// 量子密话年净增（户）
    updateCell('N7', ceilToInteger(devRow[12] ?? '0'));// 量子印章年新增（户）
    updateCell('O7', ceilToInteger(devRow[13] ?? '0'));// 直连卫星年新增（户）
    updateCell('P7', ceilToInteger(devRow[14] ?? '0'));// 直连卫星年净增（户）
    updateCell('Q7', ceilToInteger(devRow[15] ?? '0'));// 云电脑+PAD年新增（户）
    updateCell('R7', ceilToInteger(devRow[16] ?? '0'));// 云电脑+PAD年净增（户）
    updateCell('S7', ceilToInteger(devRow[18] ?? '0'));// 互联网专线年新增（条）
    updateCell('T7', ceilToInteger(devRow[17] ?? '0'));// 互联网专线年净增（条）
    updateCell('U7', ceilToInteger(devRow[20] ?? '0'));// 组网专线年新增（条）
    updateCell('V7', ceilToInteger(devRow[19] ?? '0'));// 组网专线年净增（条）
    // 第11行：收入线-收
    updateCell('C11', fullRevenue);// 全业务收入（万元）
    updateCell('D11', devRow[22] ?? 0);// 基础业务收入（万元）
    updateCell('E11', devRow[24] ?? 0);// 产数ICT收入（万元）
    updateCell('F11', devRow[23] ?? 0);// 产数资源型业务收入（万元）
    
    // 第15行：收入线-利
    updateCell('C15', fullRevenue - totalCostAssessment);// 毛利润（考核口径）= 全业务收入 - 成本合计（D15-E15）
    updateCell('D15', fullRevenue);// 全业务收入（同C11）
    updateCell('E15', totalCostAssessment);// 成本合计 = 可控成本合计 + 其他成本合计 - 网间结算 - 折旧摊销 - 产数资源型成本（C22+C26-J26-AG26-AH26）
    
    // 第18行：收入线-利
    updateCell('C18', fullRevenue - totalCostEvaluation);// 毛利润（评价口径）= 全业务收入 - 成本合计（D18-E18）
    updateCell('D18', fullRevenue);// 全业务收入（同C11）
    updateCell('E18', totalCostEvaluation);// 成本合计 = 可控成本合计 + 其他成本合计 （C22+C26)

    // 第22行：成本线
    updateCell('C22', controllableCostSum);// 可控成本合计(D22到J22总和)
    updateCell('D22', devRow[31] ?? 0);// 广宣费
    updateCell('E22', devRow[32] ?? 0);// 客户服务费
    updateCell('F22', devRow[50] ?? 0);// 业务用品
    updateCell('G22', devRow[51] ?? 0);// 办公费
    updateCell('H22', devRow[48] ?? 0);// 招待费
    updateCell('I22', devRow[43] ?? 0);// 修理费-办公类
    updateCell('J22', devRow[44] ?? 0);// 修理费-营业类
    // 第26行：其他成本
    updateCell('C26', otherCostSum);// 其他成本合计（31项）
    updateCell('D26', devRow[58] ?? 0);// 展广费-校园
    updateCell('E26', devRow[30] ?? 0);// 固网终端
    updateCell('F26', devRow[29] ?? 0);// 包区包镇
    updateCell('G26', devRow[28] ?? 0);// 社会渠道费
    updateCell('H26', devRow[26] ?? 0);// 外包费
    updateCell('I26', devRow[60] ?? 0);// ICT成本
    updateCell('J26', interOperatorSettlement);// 网间结算
    updateCell('K26', devRow[36] ?? 0);// 电费-营业厅
    updateCell('L26', devRow[37] ?? 0);// 电费-办公
    updateCell('M26', devRow[38] ?? 0);// 电费-机房基站
    updateCell('N26', devRow[39] ?? 0);// 电费-铁塔电费
    updateCell('O26', devRow[40] ?? 0);// 租费-机房基站网元
    updateCell('P26', devRow[41] ?? 0);// 租费-铁塔站址
    updateCell('Q26', devRow[42] ?? 0);// 修理费-网络类
    updateCell('R26', devRow[45] ?? 0);// 共建共享
    updateCell('S26', devRow[46] ?? 0);// 装移机料费
    updateCell('T26', devRow[25] ?? 0);// 人工成本
    updateCell('U26', devRow[27] ?? 0);// 四小补贴
    updateCell('V26', devRow[34] ?? 0);// 营业厅房租
    updateCell('W26', devRow[35] ?? 0);// 营业厅装修
    updateCell('X26', devRow[47] ?? 0);// 办公类低值易耗
    updateCell('Y26', devRow[49] ?? 0);// 邮寄费
    updateCell('Z26', devRow[52] ?? 0);// 租费
    updateCell('AA26', devRow[53] ?? 0);// 物业费
    updateCell('AB26', devRow[54] ?? 0);// 水费
    updateCell('AC26', devRow[55] ?? 0);// 取暖费
    updateCell('AD26', devRow[56] ?? 0);// 车辆使用费
    updateCell('AE26', devRow[57] ?? 0);// 校园-房租
    updateCell('AF26', devRow[59] ?? 0);// 学子公司
    updateCell('AG26', depreciationAmortization);// 折旧摊销
    updateCell('AH26', resourceCost);// 产数资源型成本 其中：产数资源型业务收入*0.2(F11*0.2)

    // 最终文件
    const fileName = `${districtName}.xlsx`;
    const filePath = path.join(SUB_DIRS.county, fileName);
    
    // 先使用 XLSXJS 写入 Buffer，保持样式
    const buffer = XLSXJS.write(workbook, {
      bookType: 'xlsx',
      type: 'buffer',
      cellStyles: true,
      bookSST: false,
      codepage: 65001 // 65001 表示 UTF-8
    });

    try {
      // 使用 ExcelJS 从 Buffer 加载
      const exceljsWorkbook = new ExcelJS.Workbook();
      await exceljsWorkbook.xlsx.load(buffer);

      const worksheet = exceljsWorkbook.getWorksheet(1); // 获取第一个sheet
      // 检查目标sheet是否存在
      const targetSheet = exceljsWorkbook.getWorksheet('支局考核激励规则');

      if (!targetSheet) {
        console.warn(`目标sheet "支局考核激励规则" 不存在，无法创建超链接`);

        // 如果sheet不存在，只添加普通文本
        const cellC30 = worksheet.getCell('C30');
        cellC30.value = '月度考核指标';
        cellC30.font = { color: { argb: 'FF0000FF' }, underline: true };
      } else {
        // 正确的超链接格式
        const cellC30 = worksheet.getCell('C30');
        const cellD30 = worksheet.getCell('D30');
        const cellE30 = worksheet.getCell('E30');
        cellC30.value = { formula: '=HYPERLINK("#支局考核激励规则!A1", "月度考核指标")' };
        cellD30.value = { formula: '=HYPERLINK("#激励!A1", "激励")' };
        cellE30.value = { formula: '=HYPERLINK("#优化!A1", "优化")' };
        cellC30.font = {
          color: { argb: 'FF0000FF' },
          underline: true
        };
        cellD30.font = {
          color: { argb: 'FF0000FF' },
          underline: true
        };
        cellE30.font = {
          color: { argb: 'FF0000FF' },
          underline: true
        };

        // 可选：添加工具提示
        cellC30.tooltip = '跳转到考核激励规则详情';
        cellD30.tooltip = '跳转详情';
        cellE30.tooltip = '跳转详情';
      }

      // 保存最终文件从 Buffer
      const finalBuffer = await exceljsWorkbook.xlsx.writeBuffer();
      try {
        await fs.writeFile(filePath, finalBuffer);
        logToFile(`生成区县文件：${filePath}`);
        // 推送通知（针对支局报告，根据局长名称）
      const mobile = personnelInfo[districtName] || '';
      if (mobile) {
        // pushTotalCountBranch++;
        // const enStr = encryptStr(mobile);
        // const pushResult = pushNotification(mobile, enStr, buffer, fileName);
        // if (pushResult.code == '0') {
        //   pushSuccessCountBranch++;
        //   logToFile(`支局推送成功：${directorName} (${mobile})`);
        // } else {
        //   logToFile(`支局推送失败：${directorName} (${mobile}), 错误: ${pushResult.error}`);
        // }
      } else {
        logToFile(`未找到支局长手机号，跳过推送：${directorName}`);
      }
        
      } catch (writeError) {
        if (writeError.code === 'EBUSY') {
          logToFile(`文件 ${filePath} 正在被其他程序打开，请关闭后重试。`);
          process.exit(1);
        } else {
          throw writeError;
        }
      }

    } catch (error) {
      console.error(`处理文件 ${districtName} 时出错:`, error);
      // 如果exceljs处理失败，回退到直接保存
      try {
        await fs.writeFile(filePath, buffer);
      } catch (fallbackError) {
        if (fallbackError.code === 'EBUSY') {
          logToFile(`文件 ${filePath} 正在被其他程序打开，请关闭后重试。`);
          process.exit(1);
        } else {
          throw fallbackError;
        }
      }
    }
  };
}

// 函数：生成支局报告
async function generateBranchReports(sheets,personnelInfo) {
  logToFile('生成支局报告...');
  if(!sheets['发展量&收入&成本目标 分解--支局']){
    logToFile(`未找到 sheet "发展量&收入&成本目标 分解--支局"，请检查数据文件sheet名称。`);
    process.exit(1);
  }
  if(!sheets['支局成本线穿透明细表']){
    logToFile(`未找到 sheet "支局成本线穿透明细表"，请检查数据文件sheet名称。`);
    process.exit(1);
  }
  if(!sheets['支局考核激励规则']){
    logToFile(`未找到 sheet "支局考核激励规则"，请检查数据文件sheet名称。`);
    process.exit(1);
  }
  const branchDevData = sheets['发展量&收入&成本目标 分解--支局'] || [];
  const branchCostData = sheets['支局成本线穿透明细表'] || [];
  const branchMotivate = sheets['支局考核激励规则'] || [];

  // 加载模板一次
  const templateWorkbook = readTemplate(TEMPLATE_PATHS.branch, 'branch.xlsx');
  const sheetName = templateWorkbook.SheetNames[0];
  const templateWs = templateWorkbook.Sheets[sheetName];

  // 全局修复 &#10; 一次
  Object.keys(templateWs).forEach(cellAddr => {
    const cell = templateWs[cellAddr];
    if (cell && cell.t === 's' && typeof cell.v === 'string' && cell.v.includes('&#10;')) {
      cell.v = cell.v.replace(/&#10;/g, '\n');
    }
  });

  //支局考核激励规则数据
  const branchManagers = {};
  branchMotivate.slice(2).forEach(row => {
    if (row[3]) {
      branchManagers[row[3]] = Array.from(row, v => v ?? 0); 
    }
  });

  //发展量&收入目标 分解--支局数据
  const branches = {};
  branchDevData.slice(3).forEach(row => {
    if (row[2]) {
      const branchName = row[2].trim(); // 支局名称
      branches[branchName] = Array.from(row, v => v ?? 0);
    }
  });

  // 支局成本线穿透明细表数据
  const branchCosts = {};
  branchCostData.slice(5).forEach(row => {
    if (row[1]) {
      branchCosts[row[1]] = row; // row[1]: 支局名称
    }
  });

  let pushSuccessCountBranch = 0;
  let pushTotalCountBranch = 0;
  
  Object.entries(branches).forEach(([branchName, devRow]) => {
    const countyName = devRow[0] ? devRow[0].trim() : ''; // 区县
    const professionalLineName = devRow[1] ? devRow[1].trim() : ''; // 专业线（用于匹配考核激励值）
    const branchAttribute = devRow[3] ? devRow[3].trim() : ''; // 支局属性
    const branchDirectorName = devRow[4] ? devRow[4].trim() : ''; // 支局长名称
    // 根据支局属性获取考核激励数据标题
    const incTitleRow = branchManagers[branchAttribute] || [];
    // 根据专业线获取考核激励数据
    const incDataRow = branchManagers[professionalLineName] || [];
    // 根据支局名称获取成本信息
    const costRow = branchCosts[branchName] || [];

    // 克隆模板
    const workbook = cloneWorkbook(templateWorkbook);
    const ws = workbook.Sheets[sheetName];

    // 直接修改模板中的单元格值，保持原有格式
    const updateCell = (cell, value) => {
      if (!ws[cell]) {
        // 如果单元格不存在，创建基本结构
        ws[cell] = { t: typeof value === 'number' ? 'n' : 's', v: value };
      } else {
        // 保留原有样式，只更新值
        ws[cell].v = value;
        ws[cell].t = typeof value === 'number' ? 'n' : 's';
      }
    };

    // 定义复用数据
    // 产数资源型成本
    const costDrBizRev = ((devRow[28] * 0.2) ?? '');
    // 战新业务成本（战新成本来源需确认）
    const costStratNewRev = (((devRow[49] ?? 0) * 0.65) ?? '');
    // 全业务收入
    const businessInc = devRow[26] ?? '';
    // 其他成本合计
    const totalCost = (
        (devRow[56] ?? '') +      // 展广费-校园
        (devRow[60] ?? 0) +     // 固网终端
        (devRow[61] ?? 0) +     // 包区包镇
        (devRow[62] ?? 0) +     // 社会渠道费
        (devRow[58] ?? 0) +     // 外包费
        (devRow[64] ?? '') +      // ICT成本
        (devRow[63] ?? 0) +     // 网间结算
        (costRow[19] ?? 0) +     // 电费-营业厅
        (costRow[20] ?? 0) +     // 电费-办公
        (costRow[21] ?? 0) +     // 电费-机房基站
        (costRow[22] ?? 0) +     // 电费-铁塔电费
        (costRow[23] ?? 0) +     // 租费-机房基站网元
        (costRow[24] ?? 0) +     // 租费-铁塔站址
        (costRow[25] ?? 0) +     // 修理费-网络类
        (costRow[26] ?? 0) +     // 共建共享
        (costRow[27] ?? 0) +      // 转移机料费
        (devRow[59] ?? '') +      //人工成本
        (devRow[45] ?? '') +       //租费-校园
        (devRow[47] ?? '') +       //学子公司
        costDrBizRev              //产数资源型成本
    );
    // 可控成本合计
    const totalControllableCost = ((devRow[50] ?? 0) + (devRow[57] ?? 0) + (devRow[51] ?? 0) + (devRow[53] ?? 0) + (devRow[52] ?? 0) + (devRow[54] ?? 0) + (devRow[55] ?? 0));
    // 毛利润（考核）成本合计
    const assCostTotal = (totalControllableCost + totalCost - (devRow[63] ?? 0) - costDrBizRev);
    // 毛利润（评价）成本合计
    const evaCostTotal = (totalControllableCost + totalCost);
    // 毛利润（考核）
    const assProfit = (businessInc - assCostTotal);
    // 毛利润（评价）
    const evaProfit = (businessInc - evaCostTotal);

    // 第2行：基本信息
    updateCell('D2', countyName);// 区县名称
    updateCell('H2',branchName);// 支局名称
    updateCell('L2', branchAttribute);// 支局属性
    updateCell('O2', branchDirectorName);// 支局长姓名
    // 第7行：发展量数据
    updateCell('C7', devRow[6] ?? '');// 移动用户年净增（万户）
    updateCell('D7', devRow[7] ?? '');// 移动用户年新增（万户）
    updateCell('E7', devRow[8] ?? '');// 宽带用户年净增（万户）
    updateCell('F7', devRow[9] ?? '');// 宽带用户年新增（万户）
    updateCell('G7', ceilToInteger(devRow[10] ?? '0'));// 151集智融合日新增（户）
    updateCell('H7', ceilToInteger(devRow[11] ?? '0'));// FTTR日新增（户）
    updateCell('I7', devRow[12] ?? '');// 高清年新增（万户）
    updateCell('J7', ceilToInteger(devRow[13] ?? '0'));// 天翼视联日新增（户）
    updateCell('K7', ceilToInteger(devRow[14] ?? '0'));// 小翼管家日新增（户）
    updateCell('L7', ceilToInteger(devRow[15] ?? '0'));// 量子密话年新增（户）
    updateCell('M7', ceilToInteger(devRow[16] ?? '0'));// 量子密话年净增（户）
    updateCell('N7', ceilToInteger(devRow[17] ?? '0'));// 量子印章年新增（户）
    updateCell('O7', ceilToInteger(devRow[18] ?? '0'));// 直连卫星年新增（户）
    updateCell('P7', ceilToInteger(devRow[19] ?? '0'));// 直连卫星年净增（户）
    updateCell('Q7', ceilToInteger(devRow[20] ?? '0'));// 云电脑+PAD年新增（户）
    updateCell('R7', ceilToInteger(devRow[21] ?? '0'));// 云电脑+PAD年净增（户）
    updateCell('S7', ceilToInteger(devRow[22] ?? '0'));// 互联网专线年净增（户）
    updateCell('T7', ceilToInteger(devRow[23] ?? '0'));// 互联网专线年新增（条）
    updateCell('U7', ceilToInteger(devRow[24] ?? '0') );// 组网专线年净增（户）
    updateCell('V7', ceilToInteger(devRow[25] ?? '0'));// 组网专线年新增（条）
    updateCell('W7', devRow[36] ?? '');// 小微DICT签约（万元）（商客）
    updateCell('X7', ceilToInteger(devRow[37] ?? '0'));// 视联网礼包新增（商客）
    updateCell('Y7', ceilToInteger((devRow[38] ?? '0')));// 商宽新增（商客）
    updateCell('Z7', ceilToInteger(devRow[39] ?? '0'));// 商宽净增（商客）
    updateCell('AA7', ceilToInteger(devRow[32] ?? '0'));// 政企团购（户）（行客）
    updateCell('AB7', ceilToInteger(devRow[33] ?? '0'));// ICT+云大单签约数量（行客）
    updateCell('AC7', devRow[34] ?? '0');// ICT+云大单签约金额（万元）（行客）
    updateCell('AD7', devRow[35] ?? '');// ICT+云商机储备金额（万元）（行客）
    // 第11行：收入数据
    updateCell('C11', businessInc);// 全业务收入
    updateCell('D11', devRow[27] ?? '');// 基础业务收入
    updateCell('E11', devRow[40] ?? '');// 互专收入（商客）
    updateCell('F11', devRow[29] ?? '');// 产数ICT收入
    updateCell('G11', devRow[28] ?? '');// 产数资源型业务收入
    updateCell('H11', devRow[41] ?? '');// 商客清单收入（商客）
    updateCell('I11', devRow[43] ?? '');// 渠道收入（校园）
    updateCell('J11', devRow[44] ?? '');// 清单收入（校园）
    updateCell('K11', devRow[49] ?? ''); // 战新收入
    // 第15行：利润 - 考核口径
    updateCell('C15', assProfit);// 毛利润（考核）
    updateCell('D15', businessInc);// 全业务收入（同A11）
    updateCell('E15', assCostTotal);// 成本合计
    // 第18行：利润 - 评价口径
    updateCell('C18', evaProfit);// 毛利润（评价）
    updateCell('D18', businessInc);// 全业务收入（同A11）
    updateCell('E18', evaCostTotal);// 成本合计
    // 第22行：成本数据
    updateCell('C22', totalControllableCost);// 可控成本合计
    updateCell('D22', devRow[50] ?? 0);// 广宣费
    updateCell('E22', devRow[57] ?? 0);// 客户服务费
    updateCell('F22', devRow[51] ?? 0);// 业务用品
    updateCell('G22', devRow[53] ?? 0);// 办公费
    updateCell('H22', devRow[52] ?? 0);// 招待费
    updateCell('I22', devRow[54] ?? 0);// 修理费-办公类
    updateCell('J22', devRow[55] ?? 0);// 修理费-营业类
    // 第26行其他成本合计
    updateCell('C26', totalCost);//其他成本合计
    updateCell('D26', devRow[56] ?? '0');//展广费-校园
    updateCell('E26', devRow[60] ?? '0');//固网终端
    updateCell('F26', devRow[61] ?? '0');//包区包镇
    updateCell('G26', devRow[62] ?? '0');//社会渠道费
    updateCell('H26', devRow[58] ?? '0');//外包费
    updateCell('I26', devRow[64] ?? '0');//ICT成本
    updateCell('J26', devRow[63] ?? '0');//网间结算
    updateCell('K26', costRow[19] ?? '0');//电费-营业厅
    updateCell('L26', costRow[20] ?? '0');//电费-办公
    updateCell('M26', costRow[21] ?? '0');//电费-机房基站
    updateCell('N26', costRow[22] ?? '0');//电费-铁塔电费
    updateCell('O26', costRow[23] ?? '0');//租费-机房基站网元
    updateCell('L26', costRow[20] ?? '0');//电费-办公
    updateCell('M26', costRow[21] ?? '0');//电费-机房基站
    updateCell('N26', costRow[22] ?? '0');//电费-铁塔电费
    updateCell('O26', costRow[23] ?? '0');//租费-机房基站网元
    updateCell('P26', costRow[24] ?? '0');//租费-铁塔站址
    updateCell('Q26', costRow[25] ?? '0');//修理费-网络类
    updateCell('R26', costRow[26] ?? '0');//共建共享
    updateCell('S26', costRow[27] ?? '0');//转移机料费
    updateCell('T26', devRow[59] ?? '0');//人工成本
    updateCell('U26', devRow[42] ?? '');//FTTR-B终端
    updateCell('V26', devRow[45] ?? '');//租费校园
    updateCell('W26', devRow[47] ?? '');//学子公司
    updateCell('X26', costDrBizRev);//产数资源型成本
    updateCell('Y26', costStratNewRev);//战新业务成本
    // 第32行 考核激励线标题
    updateCell('C32', incTitleRow[3] ?? 0);
    updateCell('D32', incTitleRow[4] ?? 0);
    updateCell('E32', incTitleRow[5] ?? 0);
    updateCell('F32', incTitleRow[6] ?? 0);
    updateCell('G32', incTitleRow[7] ?? 0);
    updateCell('H32', incTitleRow[8] ?? 0);
    updateCell('I32', incTitleRow[9] ?? 0);
    updateCell('J32', incTitleRow[10] ?? 0);
    updateCell('K32', incTitleRow[11] ?? 0);
    updateCell('L32', incTitleRow[12] ?? 0);
    updateCell('M32', incTitleRow[13] ?? 0);
    updateCell('N32', incTitleRow[14] ?? 0);
    updateCell('O32', incTitleRow[15] ?? 0);
    updateCell('P32', incTitleRow[16] ?? 0);
    updateCell('Q32', incTitleRow[17] ?? 0);
    updateCell('R32', incTitleRow[18] ?? 0);
    updateCell('S32', incTitleRow[19] ?? 0);
    updateCell('T32', incTitleRow[20] ?? 0);
    updateCell('U32', incTitleRow[21] ?? 0);
    updateCell('V32', incTitleRow[22] ?? 0);
    updateCell('W32', incTitleRow[23] ?? 0);
    updateCell('X32', incTitleRow[24] ?? 0);
    // 第33行 考核激励线数据
    updateCell('C33', incDataRow[3] ?? 0);
    updateCell('D33', incDataRow[4] ?? 0);
    updateCell('E33', incDataRow[5] ?? 0);
    updateCell('F33', incDataRow[6] ?? 0);
    updateCell('G33', incDataRow[7] ?? 0);
    updateCell('H33', incDataRow[8] ?? 0);
    updateCell('I33', incDataRow[9] ?? 0);
    updateCell('J33', incDataRow[10] ?? 0);
    updateCell('K33', incDataRow[11] ?? 0);
    updateCell('L33', incDataRow[12] ?? 0);
    updateCell('M33', incDataRow[13] ?? 0);
    updateCell('N33', incDataRow[14] ?? 0);
    updateCell('O33', incDataRow[15] ?? 0);
    updateCell('P33', incDataRow[16] ?? 0);
    updateCell('Q33', incDataRow[17] ?? 0);
    updateCell('R33', incDataRow[18] ?? 0);
    updateCell('S33', incDataRow[19] ?? 0);
    updateCell('T33', incDataRow[20] ?? 0);
    updateCell('U33', incDataRow[21] ?? 0);
    updateCell('V33', incDataRow[22] ?? 0);
    updateCell('W33', incDataRow[23] ?? 0);
    updateCell('X33', incDataRow[24] ?? 0);

    // 保存修改后的工作簿
    const fileName = `${branchName}${branchDirectorName}.xlsx`;
    const filePath = path.join(SUB_DIRS.branch, fileName); // 保存到 branch 子目录
    // 使用writeFile直接写入，保持原有格式
    try {
      XLSXJS.writeFile(workbook, filePath, {
        bookType: 'xlsx',
        type: 'file',
        cellStyles: true,
        //sheetStubs: true,
        bookSST: false,
        codepage: 65001 // 65001 表示 UTF-8
      });
      logToFile(`生成支局文件：${filePath}`);

      // 推送通知（针对支局报告，根据局长名称）
      const directorName = branchDirectorName.trim();
      const mobile = personnelInfo[directorName] || '';
      if (mobile) {
        pushTotalCountBranch++;
        const enStr = encryptStr(mobile);
        console.log(`支局手机号加密值：${enStr}`)
        // const pushResult = pushNotification(mobile, enStr, buffer, fileName);
        // if (pushResult.success) {
        //   pushSuccessCountBranch++;
        //   logToFile(`支局推送成功：${directorName} (${mobile})`);
        // } else {
        //   logToFile(`支局推送失败：${directorName} (${mobile}), 错误: ${pushResult.error}`);
        // }
      } else {
        logToFile(`未找到支局长手机号，跳过推送：${directorName}`);
      }

    } catch (writeError) {
      if (writeError.code === 'EBUSY') {
        logToFile(`文件 ${filePath} 正在被其他程序打开，请关闭后重试。`);
        process.exit(1);
      } else {
        throw writeError;
      }
    }
  });
}

// 函数：生成人员报告
async function generatePersonnelReports(sheets,personnelInfo) {
  logToFile('生成人员报告...');
  if(!sheets['发展量&收入&成本目标 分解--到人']){
    logToFile(`未找到 sheet "发展量&收入&成本目标 分解--到人"，请检查数据文件sheet名称。`);
    process.exit(1);
  }
  const personnelData = sheets['发展量&收入&成本目标 分解--到人'] || [];

  // 加载模板一次
  const templateWorkbook = readTemplate(TEMPLATE_PATHS.personnel, 'personnel.xlsx');
  const sheetName = templateWorkbook.SheetNames[0];
  const templateWs = templateWorkbook.Sheets[sheetName];

  // 全局修复 &#10; 一次
  Object.keys(templateWs).forEach(cellAddr => {
    const cell = templateWs[cellAddr];
    if (cell && cell.t === 's' && typeof cell.v === 'string' && cell.v.includes('&#10;')) {
      cell.v = cell.v.replace(/&#10;/g, '\n');
    }
  });

  const batchSize = 50; // 分批处理，每批 50 行
  let pushSuccessCount = 0;
  let pushTotalCount = 0;

  for (let start = 3; start < personnelData.length; start += batchSize) {
    const batch = personnelData.slice(start, start + batchSize);
    for (const personRow of batch) {
      if (personRow[0]) {
        // 克隆模板
        const workbook = cloneWorkbook(templateWorkbook);
        const ws = workbook.Sheets[sheetName];

        // 直接修改模板中的单元格值，保持原有格式
        const updateCell = (cell, value) => {
          if (!ws[cell]) {
            // 如果单元格不存在，创建基本结构
            ws[cell] = { t: typeof value === 'number' ? 'n' : 's', v: value };
          } else {
            // 保留原有样式，只更新值
            ws[cell].v = value;
            ws[cell].t = typeof value === 'number' ? 'n' : 's';
          }
        };

        // 定义复用数据
        const strategicNewCost = ((personRow[47] ?? 0) * 0.65); // 战新业务成本
        const resourceCost = ((strategicNewCost) * 0.2); // 产数资源型成本
        const fullRevenue = personRow[24] ?? 0; // 全业务收入
        // 毛利润（评价）成本合计
        const evaCostTotal = (
          (personRow[28] ?? 0) + // 产数ICT成本
          (personRow[43] ?? 0) + // 租费—校园
          (personRow[44] ?? 0) + // 展广费—校园
          (personRow[45] ?? 0) + // 学子公司
          (personRow[40] ?? 0) + // FTTR-B终端
          (personRow[29] ?? 0) + // 人工成本
          resourceCost          // 产数资源型成本
        );
        // 毛利润（考核）成本合计
        const assCostTotal = evaCostTotal - resourceCost;
        const assProfit = (fullRevenue - assCostTotal); // 毛利润（考核）
        const evaProfit = (fullRevenue - evaCostTotal); // 毛利润（评价）

        // 第2行：基本信息
        updateCell('C2', personRow[0] ?? ''); // 我的姓名2
        updateCell('E2', personRow[4] ?? ''); // 我的岗位
        updateCell('G2', personRow[1] ?? ''); // 区县
        updateCell('I2', personRow[3] ?? ''); // 支局
        // 第7行：移动宽带等量数据
        updateCell('B7', personRow[5] ?? 0); // 移动用户年新增（户）
        updateCell('C7', personRow[6] ?? 0); // 移动用户年净增（户）
        updateCell('D7', personRow[7] ?? 0); // 宽带用户年新增（户）
        updateCell('E7', personRow[8] ?? 0); // 宽带用户年净增（户）
        updateCell('F7', ceilToInteger(personRow[9] ?? 0)); // 151集智融合月新增
        updateCell('G7', ceilToInteger(personRow[10] ?? 0)); // FTTR月新增
        updateCell('H7', personRow[11] ?? 0); // 高清年新增
        updateCell('I7', ceilToInteger(personRow[12] ?? 0)); // 天翼视联月新增
        updateCell('J7', ceilToInteger(personRow[13] ?? 0)); // 小翼管家月新增
        updateCell('K7', ceilToInteger(personRow[14] ?? 0)); // 量子密话年新增
        updateCell('L7', ceilToInteger(personRow[15] ?? 0)); // 量子密话年净增
        updateCell('M7', ceilToInteger(personRow[16] ?? 0)); // 量子印章年新增
        updateCell('N7', ceilToInteger(personRow[17] ?? 0)); // 直连卫星年新增
        updateCell('O7', ceilToInteger(personRow[18] ?? 0)); // 直连卫星年净增
        updateCell('P7', ceilToInteger(personRow[19] ?? 0)); // 云电脑+PAD年新增
        updateCell('Q7', ceilToInteger(personRow[20] ?? 0)); // 云电脑+PAD年净增
        updateCell('R7', ceilToInteger(personRow[21] ?? 0)); // 互联网专线年新增
        updateCell('S7', ceilToInteger(personRow[22] ?? 0)); // 互联网专线年净增
        updateCell('T7', ceilToInteger(personRow[23] ?? 0)); // 组网专线年新增
        // 第12行：其他量数据
        updateCell('B12', ceilToInteger(personRow[30] ?? 0)); // 政企团购（户）
        updateCell('C12', ceilToInteger(personRow[31] ?? 0)); // ICT+云大单签约数量
        updateCell('D12', personRow[32] ?? 0); // ICT+云大单签约金额（万元）
        updateCell('E12', personRow[33] ?? 0); // ICT+云商机储备金额（万元）
        updateCell('F12', personRow[34] ?? 0); // 小微DICT签约（万元）（商客）
        updateCell('G12', ceilToInteger(personRow[35] ?? 0)); // 视联网礼包新增（商客）
        updateCell('H12', ceilToInteger(personRow[36] ?? 0)); // 商宽新增（商客）
        updateCell('I12', ceilToInteger(personRow[37] ?? 0)); // 商宽净增（商客）
        // 第16行：收入数据
        updateCell('B16', fullRevenue); // 全业务收入
        updateCell('C16', personRow[25] ?? 0); // 基础业务收入
        updateCell('D16', personRow[26] ?? 0); // 产数资源型业务收入
        updateCell('E16', personRow[27] ?? 0); // 产数ICT收入
        updateCell('F16', personRow[38] ?? 0); // 互专收入（商客）
        updateCell('G16', personRow[39] ?? 0); // 商客清单收入（商客）
        updateCell('H16', personRow[41] ?? 0); // 渠道收入（校园）
        updateCell('I16', personRow[42] ?? 0); // 清单收入（校园）
        updateCell('J16', personRow[47] ?? 0); // 战新收入
        // 第21行：利润 - 考核口径
        updateCell('B21', assProfit); // 毛利润（考核）
        updateCell('C21', fullRevenue); // 全业务收入（同A16）
        updateCell('D21', assCostTotal); // 成本合计
        // 第24行：利润 - 评价口径
        updateCell('B24', evaProfit); // 毛利润（评价）
        updateCell('C24', fullRevenue); // 全业务收入（同A16）
        updateCell('D24', evaCostTotal); // 成本合计
        // 第28行：成本数据
        updateCell('B28', personRow[28] ?? 0); // 产数ICT成本
        updateCell('C28', personRow[43] ?? 0); // 租费—校园
        updateCell('D28', personRow[44] ?? 0); // 展广费—校园
        updateCell('E28', personRow[45] ?? 0); // 学子公司
        updateCell('F28', personRow[40] ?? 0); // FTTR-B终端
        updateCell('G28', personRow[29] ?? 0); // 人工成本
        updateCell('H28', resourceCost); // 产数资源型成本
        updateCell('I28', strategicNewCost); // 战新业务成本

        // 保存修改后的工作簿到 Buffer
        const buffer = XLSXJS.write(workbook, {
          bookType: 'xlsx',
          type: 'buffer',
          cellStyles: true,
          bookSST: false,
          codepage: 65001 // 65001 表示 UTF-8
        });
        
        const fileName = `${personRow[0].trim()}.xlsx`;
        const filePath = path.join(SUB_DIRS.personnel, fileName); // 保存到 personnel 子目录

        // 使用exceljs添加超链接
        try {
          const exceljsWorkbook = new ExcelJS.Workbook();
          await exceljsWorkbook.xlsx.load(buffer);
          
          const worksheet = exceljsWorkbook.getWorksheet(1); // 获取第一个sheet
          
          // 检查目标sheet是否存在
          const targetSheet = exceljsWorkbook.getWorksheet('一线触点人员考核激励规则');
          
          if (!targetSheet) {
            console.warn(`目标sheet "一线触点人员考核激励规则" 不存在，无法创建超链接`);
            
            // 如果sheet不存在，只添加普通文本
            const cellB33 = worksheet.getCell('B33');
            cellB33.value = '查看考核激励规则';
            cellB33.font = { color: { argb: 'FF0000FF' }, underline: true };
          } else {
            // 正确的超链接格式
            const cellB33 = worksheet.getCell('B33');
            cellB33.value = { formula: '=HYPERLINK("#一线触点人员考核激励规则!A1", "查看考核激励规则")' };
            cellB33.font = {
              color: { argb: 'FF0000FF' },
              underline: true
            };
            
            // 可选：添加工具提示
            cellB33.tooltip = '跳转到考核激励规则详情';
          }
        
          // 保存最终文件从 Buffer
          const finalBuffer = await exceljsWorkbook.xlsx.writeBuffer();
          try {
            await fs.writeFile(filePath, finalBuffer);
            logToFile(`生成人员文件：${filePath}`);

            // 推送通知（仅针对人员报告）
            const personName = personRow[0].trim();
            const mobile = personnelInfo[personName] || '';
            if (mobile) {
              pushTotalCount++;
              const enStr = encryptStr(mobile);
              console.log(`人员手机号加密值：${enStr}`)
              // const pushResult = await pushNotification(mobile, enStr, finalBuffer, fileName);
              // if (pushResult.success) {
              //   pushSuccessCount++;
              //   logToFile(`推送成功：${personName} (${mobile})`);
              // } else {
              //   logToFile(`推送失败：${personName} (${mobile}), 错误: ${pushResult.error}`);
              // }
            } else {
              logToFile(`未找到手机号，跳过推送：${personName}`);
            }

          } catch (writeError) {
            if (writeError.code === 'EBUSY') {
              logToFile(`文件 ${filePath} 正在被其他程序打开，请关闭后重试。`);
              process.exit(1);
            } else {
              throw writeError;
            }
          }
          
        } catch (error) {
          console.error(`处理文件 ${personRow[0]} 时出错:`, error);
          // 如果exceljs处理失败，至少保留 buffer
          try {
            await fs.writeFile(filePath, buffer);
          } catch (fallbackError) {
            if (fallbackError.code === 'EBUSY') {
              logToFile(`文件 ${filePath} 正在被其他程序打开，请关闭后重试。`);
              process.exit(1);
            } else {
              throw fallbackError;
            }
          }
        }
      }
    }
  }
}

// 直接执行生成逻辑
(async () => {
  const startTime = Date.now();  // 添加：记录开始时间
  logToFile('开始生成报告...');
  try {
    logToFile('创建输出目录...');
    await mkdirp(OUTPUT_DIR);
    await mkdirp(SUB_DIRS.county); // 创建区县子目录
    await mkdirp(SUB_DIRS.branch); // 创建支局子目录
    await mkdirp(SUB_DIRS.personnel); // 创建人员子目录
    logToFile('输出目录创建成功：', OUTPUT_DIR);

    // 读取并解析输入的 Excel 文件
    const sheets = readInputExcel();

    // 读取并解析输入的 人员数据Excel 文件
    const personnelInfo = readInputUserExcel();

    // // 读取人员信息 sheet，建立姓名到手机号的映射（假设第1列姓名，第2列手机号，从第2行开始数据）
    // const personnelSheet = sheets['人员信息'] || [];
    // const personnelInfo = {};
    // personnelSheet.slice(1).forEach(row => { // 跳过标题行
    //   if (row[0] && row[1]) {
    //     const name = row[0].toString().trim();
    //     const mobile = row[1].toString().trim();
    //     personnelInfo[name] = mobile;
    //   }
    // });
    // logToFile(`加载人员信息：${Object.keys(personnelInfo).length} 条记录`);

    // 逐个生成报告，避免同时加载所有 sheet
    logToFile('开始生成区县报告...');
    await generateDistrictReports(sheets,personnelInfo);
    logToFile('开始生成支局报告...');
    await generateBranchReports(sheets,personnelInfo);
    logToFile('开始生成人员报告...');
    await generatePersonnelReports(sheets,personnelInfo);
    const files = [];
    // 递归收集所有子目录中的文件
    for (const subDir of Object.values(SUB_DIRS)) {
      const subDirFiles = await fs.readdir(subDir);
      subDirFiles.forEach(file => {
        if (file.endsWith('.xlsx')) {
          files.push(path.join(subDir, file));
        }
      });
    }
    logToFile('生成的文件数：', files.length);
    logToFile('报告生成完成');

    // 打包 files 目录为 zip
    logToFile('开始打包 files 目录...');
    const zipPath = path.join(path.dirname(OUTPUT_DIR), 'reports.zip');
    await zipDirectory(OUTPUT_DIR, zipPath);
    logToFile(`打包完成：${zipPath}`);

    // 删除生成的文件（保留 zip）
    logToFile('删除生成的文件...');
    for (const subDir of Object.values(SUB_DIRS)) {
      await fs.emptyDir(subDir);
    }
    logToFile('文件删除完成');

    const endTime = Date.now();  // 添加：记录结束时间
    const executionTime = endTime - startTime;  // 计算执行时间（毫秒）
    logToFile(`总执行时间: ${executionTime} ms (${Math.round(executionTime / 1000)} 秒)`);  // 输出到日志和控制台
  } catch (error) {
    console.error('生成报告失败：', error.message);
    console.error('错误堆栈：', error.stack);
  } finally {
    // 在EXE模式下，执行完毕后等待用户输入再关闭窗口
    if (isPackaged) {
      logToFile('报告生成完成，按任意键退出...');
      const stdin = process.stdin;
      stdin.setRawMode(true);
      stdin.resume();
      stdin.once('data', () => {
        stdin.pause();
        process.exit(0);
      });
    }
  }
})();